package pv;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * 信号量
 * <p> p、v 是原子操作, 由开/关中断实现</p>
 *
 * @author yezh
 * @date 2024/7/4 9:59
 */
public class Semaphore {

    private final boolean printLog = false;

    private AtomicInteger value;
    private final LinkedList<Thread> waiters = new LinkedList<>();
    private String name;

    public Semaphore(int value) {
        this.value = new AtomicInteger(value);
    }

    public Semaphore(int value, String name) {
        this.value = new AtomicInteger(value);
        this.name = name;
    }

    public void p() {
        if (value.decrementAndGet() < 0) {
            block(Thread.currentThread());
        }
        if (printLog) {
            System.out.println(name + " (" + Thread.currentThread().getName() + ") 获取资源, 剩余资源：" + value.get());
        }
    }

    public void v() {
        if (value.incrementAndGet() <= 0) {
            wakeup();
        }
        if (printLog) {
            System.out.println(name + " (" + Thread.currentThread().getName() + ") 释放资源, 剩余资源：" + value.get());
        }
    }

    private void block(Thread t) {
        synchronized (waiters) {
            waiters.addLast(t);
            if (printLog) {
                System.out.println(name + " (" + t.getName() + ")挂起 - 等待队列剩余线程数: " + waiters.size());
            }
        }
        LockSupport.park(t);
    }

    private void wakeup() {
        Thread t;
        synchronized (waiters) {
            t = waiters.pollFirst();
            if (printLog) {
                System.out.println(name + " (" + Thread.currentThread().getName() + ")唤起 - 等待队列剩余线程数: " + waiters.size());
            }
        }
        LockSupport.unpark(t);
    }

}
